<template>
  <div>
    <div v-if="imageUrl" @click="openUpload()" class="imgBox flex justify_center alignCenter">
      <img :src="imageUrl"/>
    </div>
    <div v-if="!imageUrl" @click="openUpload()" class="iconBox flex justify_center alignCenter">
      <i style="font-size:30px; color: #909399;" class="el-icon-picture-outline"></i>
    </div>

    <CommonMiniDialog :add="show" :title="title" :width="dialogWidth" @closeMiniDialog="closeShow">
      <template #content>
        <!--上传按钮-->
        <el-upload accept="image/png, image/jpeg, image/gif, image/jpg" ref="fileUpload"
                   :name="uploadFile.fileName" :action="action" :data="dataParam" :on-change="selectChange"
                   :show-file-list="false" :auto-upload="false"
                   :http-request="httpRequest">
          <div>
            <el-button class="upLoadBtn" type="success" plain>
              <i class="el-icon-upload2"></i>&nbsp; 上传
            </el-button>
          </div>
        </el-upload>
        <div class="upLoadSignInfo">文件大小不超过2M，建议尺寸40px*40px</div>
        <!--剪切图片组件-->
        <div style="display: flex" :class="showView ? '':'cutCenter'">
          <div class="cut">
            <vue-cropper
              ref="cropper"
              :img="option.img !== '' ? option.img : imageUrl"
              :output-size="option.size"
              :output-type="option.outputType"
              :info="option.info"
              :full="option.full"
              :fixed="option.fixed"
              :fixed-number="option.fixedNumber"
              :can-move="option.canMove"
              :can-move-box="option.canMoveBox"
              :fixed-box="option.fixedBox"
              :original="option.original"
              :auto-crop="option.autoCrop"
              :auto-crop-width="option.autoCropWidth"
              :auto-crop-height="option.autoCropHeight"
              :center-box="option.centerBox"
              @real-time="realTime"
              :high="option.high"
              mode="cover"
              :max-img-size="option.max"
              :canScale="option.canScale"
              :infoTrue="option.infoTrue"
              :maxImgSize="option.maxImgSize"
              :enlarge="option.enlarge"
              :mode="option.mode"
              :limitMinSize="option.limitMinSize"
              :fillColor="option.fillColor"
            >
            </vue-cropper>
          </div>
          <!--预览剪切图片-->
          <div class="show-preview" v-if="showView"
               :style="{'width': previews.w + 'px', 'height': previews.h + 'px',  'overflow': 'hidden', 'margin-left': '5px'}">
            <div :style="previews.div">
              <img :src="previews.url" :style="previews.img" alt="">
            </div>
          </div>
        </div>

        <!--对图片的一些操作-->
        <div class="menuBox" v-if="optBtn">
          <div class="menuBtn el-icon-scissors" :class="optBtnCheckValue === 'startCrop' ? 'menuBtnCheck':''"
               @click="startCrop('startCrop')" title="开始截图"></div>
          <div class="menuBtn el-icon-circle-check" :class="optBtnCheckValue === 'stopCrop' ? 'menuBtnCheck':''"
               @click="stopCrop('stopCrop')" title="停止截图"></div>
          <div class="menuBtn el-icon-circle-close" :class="optBtnCheckValue === 'clearCrop' ? 'menuBtnCheck':''"
               @click="clearCrop('clearCrop')" title="清除截图"></div>
          <div class="menuBtn el-icon-zoom-in" :class="optBtnCheckValue === 'amplify' ? 'menuBtnCheck':''"
               @click="changeScale(1,'amplify')" title="放大"></div>
          <div class="menuBtn el-icon-zoom-out" :class="optBtnCheckValue === 'shrink' ? 'menuBtnCheck':''"
               @click="changeScale(-1,'shrink')" title="缩小"></div>
          <div class="menuBtn el-icon-back" :class="optBtnCheckValue === 'rotateLeft' ? 'menuBtnCheck':''"
               @click="rotateLeft('rotateLeft')" title="左旋转90°"></div>
          <div class="menuBtn el-icon-right" :class="optBtnCheckValue === 'rotateRight' ? 'menuBtnCheck':''"
               @click="rotateRight('rotateRight')" title="右旋转90°"></div>
        </div>

        <!--弹出框的确认上传和取消-->
        <div class="test-button">
          <el-button class="closeBtn" @click="closeShow">取 消</el-button>
          <el-button v-if="!isLoading" class="sureBtn" @click="clickSure" type="primary">确 定</el-button>
          <el-button v-else class="sureBtn" type="primary" :loading="isLoading">上传中</el-button>
        </div>
      </template>
    </CommonMiniDialog>
  </div>
</template>
<script>

import {VueCropper} from 'vue-cropper'
import BaseComp from "./baseComp";
import CommonMiniDialog from "./commonMiniDialog.vue";

export default {
  name: "imgEdit",
  model: {
    prop: "imageUrl",
    event: "imageUrlChange",
  },
  extends: BaseComp,
  components: {
    VueCropper,CommonMiniDialog
  },
  data() {

    return {
      show: false, // 显示裁剪弹窗
      previews: {}, // 预览截屏数据
      option: {
        img: '',  // 上传图片地址
        size: 1,  // 输出图片大小
        full: true,  // 是否输出原图比例
        outputType: 'png',  // 输出图片格式
        canMove: true, // 图片是否可移动
        info: true,
        canScale: true, // 图片是否允许滚轮缩放
        fixedBox: false,  // 截图框是否固定
        original: true,  // 图片是否按比例
        canMoveBox: true, // 截图框是否可移动
        autoCrop: true,  // 是否开启截图
        // 只有自动截图开启 宽度高度才生效
        autoCropWidth: '40',  // 输出图片宽高
        autoCropHeight: '40',  // 输出图片宽高
        centerBox: false,  // 是否开启截图框固定宽高
        high: true,  // 是否按照设备的dpr 输出等比例图片
        max: 99999,  // 输出图片大小限制
        fixed: false,  // 是否开启截图框宽高固定比例
        fixedNumber: [16, 9],  // 截图框的宽高比例, 开启fixed生效
        infoTrue: false, // true 为展示真实输出图片宽高 false 展示看到的截图框宽高
        maxImgSize: 2000, // 限制图片最大宽度和高度
        enlarge: 1,
        mode: 'contain',
        limitMinSize: 10,
        fillColor: '#ffffff'

      }, // 截图配置参数
      isLoading: false,  // 是否在上传
      // 上传的文件信息
      uploadFile: {
        file: "",
        fileName: ""
      },
      optBtnCheckValue: 'startCrop'
    }
  },
  props: {
    title: {
      type: String,
      default: "上传图片"
    },
    dialogWidth: {
      type: String,
      default: "30%"
    },
    // 截屏后图片
    imageUrl: {
      type: String
    },
    // 截图参数
    cropOption: {
      type: Object,
      default: () => {
        return this.option
      },
    },
    // 上传图片 大小限制
    imgUploadSize: {
      type: [Number,String],
      default: 2,
    },
    // 上传文件类型
    saveFileType: {
      type: String,
      default: "base64"
    },
    // 图片服务器上传地址
    action: {
      type: String,
      default: '',
    },
    // 上传文件名
    customFileName: {
      type: String
    },
    // 上传时附带的额外参数
    dataParam: {
      type: Object,
      default: () => {
      },
    },
    dicFormatter:{
      type: [String,Function]
    },
    optBtn:{
      type: Boolean,
      default: true
    },
    showView:{
      type: Boolean,
      default: true
    }
  },
  watch: {
    'cropOption': {
      handler(v) {
        if (!v.img){
          v.img = "";
        }
        this.option = v;
      },
      immediate: true,
      deep: true
    },
    "imageUrl":{
      handler(v) {
        if(v){
          this.option.img = v;
        }
      },
      immediate: true,
      deep: true
    }
  },
  methods: {

    //打开上传图片弹框
    openUpload() {
      this.show = true;
    },
    // 关闭上传图片弹框
    closeShow() {
      // 清空剪切栏的图片数据
      this.show = false
      this.isLoading = false;
    },
    // 删除
    delete() {
      this.$emit("imageUrlChange", "")
    },
    // 放大缩小
    changeScale(num, value) {
      this.optBtnCheckValue = value
      num = num || 1
      this.$refs.cropper.changeScale(num)
    },
    // 左旋转
    rotateLeft(value) {
      this.optBtnCheckValue = value
      this.$refs.cropper.rotateLeft()
    },
    // 右旋转
    rotateRight(value) {
      this.optBtnCheckValue = value
      this.$refs.cropper.rotateRight()
    },
    // 开始截图
    startCrop(value) {
      this.optBtnCheckValue = value
      this.$refs.cropper.startCrop()
    },
    // 停止截图
    stopCrop(value) {
      this.optBtnCheckValue = value
      this.$refs.cropper.stopCrop()
    },
    // 清除截图
    clearCrop(value) {
      this.optBtnCheckValue = value
      this.uploadFile.file = ""
      this.$emit("imageUrlChange", "")
      this.$refs.cropper.clearCrop()
    },
    // 实时预览函数
    realTime(data) {
      this.previews = data
    },
    clickSure() {
      this.isLoading = true
      // 不上传，直接保存base64格式数据
      if (this.saveFileType == 'base64') {
        this.$refs.cropper.getCropData(data => {
          this.$emit("imageUrlChange", data)
          this.isLoading = false;
          this.show = false
        });
      } else {
        this.$refs.cropper.getCropBlob(async (data) => {
          let imageUrl = window.URL.createObjectURL(data);
          this.$emit("imageUrlChange", imageUrl)
          this.uploadImg(data)
        })
      }
    },

    // 选择文件
    selectChange(file) {
      const {raw, name} = file;
      this.openCropper(raw);
      this.uploadFile.fileName = name; // 文件名字（需要传递-否则服务器异常）
    },
    // 截图
    openCropper(file) {
      let files = file;
      let isLt2M = (files.size / 1024 / 1024) > this.imgUploadSize;
      if (isLt2M) {
        this.$message.error(`请上传${this.imgUploadSize}M内的图片`);
        return false;
      }
      let reader = new FileReader();
      reader.onload = e => {
        let data;
        if (typeof e.target.result === 'object') {
          // 把Array Buffer转化为blob 如果是base64不需要
          data = window.URL.createObjectURL(new Blob([e.target.result]));
        } else {
          data = e.target.result;
        }
        this.option.img = data
      };
      // 下面两种方式都可以
      // 转化为base64
      reader.readAsDataURL(files)
      // 转化为blob
      // reader.readAsArrayBuffer(files);
    },

    // 上传图片
    uploadImg(file) {
      this.uploadFile.file = file;
      this.$refs.fileUpload.submit();
      this.$refs.fileUpload.clearFiles(); // 每次submit 都情况下文件列表，避免重复上传之前的文件（多次上传问题）
    },

    // submit 之后会触发此方法
    httpRequest(request) {
      const {action, data, filename} = request;
      // 新建formDate对象
      let formData = new FormData();
      for (let key in this.dataParam) {
        formData.append(key, data[key]);
      }
      // 文件单独push,第三个参数指定上传的文件名
      formData.append(filename, this.uploadFile.file, this.customFileName ? this.customFileName : this.uploadFile.fileName);
      if (action) {
        this.$myAxios.send({
          headers: {
            contentType: 'multipart/form-data' // 需要指定上传的方式
          },
          url: action,
          method: 'post',
          data: formData,
          timeout: 200000000 // 防止文件过大超时
        }).then(({data: resp}) => {
          let dicFormatter = this.dicFormatter;
          if (typeof dicFormatter != "function") {
            dicFormatter = eval(dicFormatter);
          }
          let responseData = dicFormatter(resp.data);
          this.$emit("imageUrlChange", responseData)
        }).catch(err => {
          console.log(err)
          this.$message.error(err)
        });
      }
    },
  },
}
</script>
<style type="less" scoped>
* {
  margin: 0;
  padding: 0;
}

.cut {
  width: 300px;
  height: 300px;
  flex-shrink: 0;
  display: flex;
  margin-bottom: 20px;
  box-sizing: border-box;
  overflow: hidden;
  .cropper-modal{
    background: rgb(0 0 0 / 0%);
  }
}

.test-button {
  display: flex;
  align-content: center;
  justify-content: flex-end;
}

.imgBox {
  cursor: pointer;
  width: auto;
  height: auto;
  border: 1px solid #cacaca;
  border-radius: 2px;
}

.iconBox {
  cursor: pointer;
  width: 50px;
  height: 50px;
  border: 1px solid #cacaca;
  border-radius: 2px;
}

.sureBtn {
  display: inline-block;
  line-height: 1;
  white-space: nowrap;
  cursor: pointer;
  text-align: center;
  box-sizing: border-box;
  outline: none;
  margin: 20px 10px 0 0;
  padding: 9px 15px;
  font-size: 14px;
  border-radius: 4px;
  color: #fff;
  background-color: #409EFF;
  border-color: #409EFF;
  transition: all .2s ease;
  text-decoration: none;
  user-select: none;
}

.closeBtn {
  display: inline-block;
  line-height: 1;
  white-space: nowrap;
  cursor: pointer;
  background: #fff;
  border: 1px solid #c0ccda;
  color: #1f2d3d;
  text-align: center;
  box-sizing: border-box;
  outline: none;
  margin: 20px 10px 0 0;
  padding: 9px 15px;
  font-size: 14px;
  border-radius: 4px;
  transition: all .2s ease;
  text-decoration: none;
  user-select: none;
}

.menuBox {
  display: flex;
  box-sizing: border-box;
  align-items: center;
  height: 30px;
  width: 460px;
  justify-content: center;
}

.menuBtn {
  white-space: nowrap;
  cursor: pointer;
  background: #ff4d51;
  color: #fff;
  text-align: center;
  box-sizing: border-box;
  outline: none;
  margin-right: 10px;
  padding: 9px 15px;
  font-size: 14px;
  border-radius: 4px;
  transition: all .2s ease;
  text-decoration: none;
  user-select: none;
  height: 30px;
  width: 50px;
}

.menuBtnCheck {
  background: #67C23A;
}

code.language-html {
  padding: 10px 20px;
  margin: 10px 0;
  display: block;
  background-color: #333;
  color: #fff;
  overflow-x: auto;
  font-family: Consolas, Monaco, Droid, Sans, Mono, Source, Code, Pro, Menlo, Lucida, Sans, Type, Writer, Ubuntu, Mono;
  border-radius: 5px;
  white-space: pre;
}

@keyframes slide {
  0% {
    background-position: 0 0;
  }
  100% {
    background-position: -100% 0;
  }
}

.upLoadBtn {
  width: 70px;
  height: 32px;
  background-color: #FFFFFF;
  color: #7ECB57;
}

.upLoadSignInfo {
  color: #D2D2D2;
  margin: 10px 0
}

.cutCenter{
  justify-content: center
}

</style>
